<?php
class FileSystem
{
	private $master;
	private $cacheHost;
	private $parseWithUrl;
	private $logFunc;

	const IMAGE_TYPE_SWF = 0;
	const IMAGE_TYPE_GIF = 1;
	const IMAGE_TYPE_JPG = 2;
	const IMAGE_TYPE_PNG = 3;

	function __construct($conf)
	{
		$this->master = empty($conf['master']) ? 'http://localhost:9333' : 'http://'.$conf['master'];
		$this->cacheHost = empty($conf['cache_host']) ? false : $conf['cache_host'];
		$this->parseWithUrl = empty($conf['parse_with_url']) ? false : $conf['parse_with_url'];
		if (isset($conf['log_func']) && is_callable($conf['log_func'])) {
			$this->logFunc = $conf['log_func'];
		}
	}

	function saveImage($path, $cacheHost = false)
	{
		list($width, $height, $type) = getimagesize($path);
		$ext = '';
		$format = 0;
		switch($type) {
			case 4:
			case 13:
				$format = self::IMAGE_TYPE_SWF;
				$ext = 'swf';
				$fileType = 'application/x-shockwave-flash';
				break;
			case 1:
				$format = self::IMAGE_TYPE_GIF;
				$ext = 'gif';
				$fileType = 'image/gif';
				break;
			case 2:
				$format = self::IMAGE_TYPE_JPG;
				$ext = 'jpg';
				$fileType = 'image/jpeg';
				break;
			case 3:
				$format = self::IMAGE_TYPE_PNG;
				$fileType = 'image/png';
				$ext = 'png';
				break;
			default:
				throw new Exception('filesystem.u_wrongFormat type='.$type);
		}
		

		$curl = LibUtil::load('Curl');
		$url = $this->master.'/dir/assign';
		$ret = $curl->get($url);
		if ($this->logFunc) {
			call_user_func($this->logFunc, 'fs.curl'.$url.':'.$ret['content']);
		}
		$content = json_decode($ret['content'], true);
		$oriId = $content['fid'];
		list($volumeId) = explode($oriId, ',');

		$fileId = $this->_getFileId($oriId, $width, $height, $format);

		$publicUrl = $content['publicUrl'];
		$url = sprintf('http://%s/%s', $publicUrl, $fileId['str']);
		$ret = $curl->post($url, array('file' => '@'.$path.';type='.$fileType), array(), 0, false);
		if ($this->logFunc) {
			call_user_func($this->logFunc, 'fs.curl'.$url.':'.$ret['content']);
		}
		
		$content = json_decode($ret['content'], true);
		$fileId['url'] = $url;
		$fileId['ext'] = $ext;
		$fileId['width'] = $width;
		$fileId['height'] = $height;

		if ($this->cacheHost) {
			$this->_setVolumeHost($volumeId, $publicUrl);
		}
		return $fileId;
	}

	function parseFileId($fileId)
	{
		$fileId = strtolower($fileId);
		$ret['volume_id'] = base_convert(ltrim(substr($fileId, 0, 4), '0'), 16, 10);
		$ret['file_guid'] = ltrim(substr($fileId, 4, 16), '0');
		$ret['file_cookie'] = substr($fileId, 20, 8);
		$fileCookie = base_convert($ret['file_cookie'], 16, 10);
		$ret['width'] = $fileCookie >> 19;
		$ret['height'] = $fileCookie >> 6 & ((1 << 13) - 1);
		$ret['type'] = $fileCookie >> 2 & ((1 << 4) - 1);

		switch($ret['type']) {
			case self::IMAGE_TYPE_SWF:
				$ret['ext'] = 'swf';
				break;
			case self::IMAGE_TYPE_JPG:
				$ret['ext'] = 'jpg';
				break;
			case self::IMAGE_TYPE_PNG:
				$ret['ext'] = 'png';
				break;
			case self::IMAGE_TYPE_GIF:
				$ret['ext'] = 'gif';
				break;
		}
		$ret['fid'] = sprintf('%s,%s%s', $ret['volume_id'], $ret['file_guid'], $ret['file_cookie']);
		if ($this->parseWithUrl) {
			$publicUrl = $this->_getVolumeHost($ret['volume_id']);
			$ret['url'] = sprintf('http://%s/%s.%s', $publicUrl, $ret['fid'], $ret['ext']);
		}
		return $ret;
	}

	private function _getVolumeHost($volumeId)
	{
		$cacheKey = 'volume.host.'.$volumeId;
		$cache = Com::get('cache');
		$publicUrl = $cache->get($cacheKey);
		if ($publicUrl === null) {
			$curl = LibUtil::load('Curl');
			$url = sprintf('%s/dir/lookup?volumeId=%s&pretty=y', $this->master, $volumeId);
			$body = $curl->get($url);
			if ($this->logFunc) {
				call_user_func($this->logFunc, 'fs.curl'.$url.':'.$body['content']);
			}
			$content = json_decode($body['content'], true);
			$publicUrl = $content['locations'][0]['publicUrl'];
			$this->_setVolumeHost($volumeId, $publicUrl);
		}
		return $publicUrl;
	}

	private function _setVolumeHost($volumeId, $host)
	{
		Com::get('cache')->set('volume.host.'.$volumeId, $host, 30 * 60);
	}

	public function _getFileId($oriId, $width, $height, $format)
	{
		list($volumeId, $else) = explode(',', $oriId);
		$fileCookie = substr($else, -8);

		$nfileCookie = $this->_getFileCookie($width, $height, $format);
		$nfileCookie = $fileCookie & 3 | $nfileCookie;
		$ret = array(
			'str' => sprintf('%s,%s', $volumeId, substr($else, 0, -8).base_convert($nfileCookie, 10, 16)),
			'hex' => sprintf('0x%04x%016s%08x',
				$volumeId,
				substr($else, 0, -9),
				$nfileCookie
			),
		);
		return $ret;
	}



	private function _getFileCookie($width, $height, $format)
	{
		return $width << 19 | $height << 6 | $format << 2;
	}
}